package com.prb.factory;

import com.prb.annotation.*;
import com.prb.bean.BeanDefinition;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class AnnotationBeanFactory {

    private static Map<String , Object> beanMap = new ConcurrentHashMap<>();

    private static Map<String , BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    public static void doScan(String pagePath) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {

        File file = getFile(pagePath);

        //构建 BeanDefinition
        buildBeanDefinition(file);

        //创建bean
        doCreateBean();

        //进行依赖注入
        injectBean();

        //扫描@Transactional 进行添加代理
        addTransactionProxy();

    }

    private static void addTransactionProxy() {
        for (Map.Entry<String, Object> entry : beanMap.entrySet()) {
            Object value = entry.getValue();
            Class<?> clazz = value.getClass();
            Transactional annotation = clazz.getAnnotation(Transactional.class);
            if(annotation != null){
                Class<?>[] interfaces = clazz.getInterfaces();
                if(interfaces.length == 1){
                    value = TransactionalProxyFactory.getJdkProxy(value);
                }else{
                    value = TransactionalProxyFactory.getCglibProxy(value);
                }
                beanMap.put(entry.getKey() , value);
            }else{
                Method[] declaredMethods = clazz.getDeclaredMethods();

                for (Method declaredMethod : declaredMethods) {
                    annotation = declaredMethod.getAnnotation(Transactional.class);
                    if(annotation != null){
                        //根据判断是否有接口 ， 来决定使用jdk代理 还是 cglib代理
                        Class<?>[] interfaces = clazz.getInterfaces();
                        if(interfaces.length == 1){
                            value = TransactionalProxyFactory.getJdkProxy(value);
                        }else{
                            value = TransactionalProxyFactory.getCglibProxy(value);
                        }
                        beanMap.put(entry.getKey() , value);
                        break;
                    }
                }
            }
        }

    }

    private static void injectBean() throws IllegalAccessException, ClassNotFoundException, InstantiationException {

        for (Map.Entry<String, Object> entry : beanMap.entrySet()) {

            Object value = entry.getValue();

            Field[] fields = value.getClass().getDeclaredFields();

            for (Field field : fields) {
                Autowrite annotation = field.getAnnotation(Autowrite.class);
                if(annotation != null){
                    Object injectBean = getInjectBean(field , annotation);
                    field.setAccessible(true);
                    field.set(value , injectBean);
                }
            }

        }

    }

    private static Object getInjectBean(Field field , Autowrite annotation) throws IllegalAccessException, ClassNotFoundException, InstantiationException {
        Object injectBean;
        if(!annotation.value().equals("")){
            injectBean = getBean(annotation.value());
        }else{
            String name = field.getName();
            injectBean = getBean(name);
        }

        return injectBean;
    }

    private static void doCreateBean() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {

            BeanDefinition beanDefinition = entry.getValue();

            //非懒加载，直接创建bean
            if(beanDefinition.getIsLazy() ==0){
                String path = beanDefinition.getPath();
                Object bean = PrbFactoryBean.createBean(path);
                beanMap.put(beanDefinition.getBeanId() , bean);
            }
        }

    }


    public static void buildBeanDefinition(File file) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, InstantiationException {

        if(file.isDirectory()){
            File[] files = file.listFiles();
            for (File file1 : files) {
                buildBeanDefinition(file1);
            }
        }else{
            String path = file.getPath();
            if(path.contains(".class")){
                //解析成class全路径
                String classPath = path.split("classes\\\\")[1].replace("\\", ".").replace(".class", "");
                //获取Class对象
                Class<?> aClass = Class.forName(classPath);
                //判断Class是否有Compoant注解
                Compoant annotation = aClass.getAnnotation(Compoant.class);
                if(annotation != null){
                    String beanId = getBeanId(aClass);
                    BeanDefinition beanDefinition = new BeanDefinition();
                    beanDefinition.setBeanId(beanId);
                    beanDefinition.setClassName(aClass.getSimpleName());
                    beanDefinition.setPath(classPath);
                    beanDefinition.setIsLazy(annotation.isLazy());
                    beanDefinition.setIsSingleton(annotation.isSingleton());
                    beanDefinitionMap.put(beanId , beanDefinition);
                }

                Configuration configuration = aClass.getAnnotation(Configuration.class);
                if(configuration != null){

                    Method[] declaredMethods = aClass.getDeclaredMethods();
                    for (Method declaredMethod : declaredMethods) {
                        Bean bean = declaredMethod.getAnnotation(Bean.class);
                        if(bean != null){
                            Class<?> returnType = declaredMethod.getReturnType();
                            String beanId = getBeanId(returnType);
                            beanMap.put(beanId , declaredMethod.invoke(aClass.newInstance()));
                        }
                    }

                }

            }
        }
    }

    public static Object getBean(String beanId) throws IllegalAccessException, InstantiationException, ClassNotFoundException {

        Object bean = beanMap.get(beanId);
        //进行懒加载
        if(bean == null){
            //可能会有安全问题 使用 dcl 防止对象的创建安全
            synchronized (AnnotationBeanFactory.class){
                bean = beanMap.get(beanId);
                if(bean == null){
                    BeanDefinition beanDefinition = beanDefinitionMap.get(beanId);
                    bean = PrbFactoryBean.createBean(beanDefinition.getPath());
                    //如果bean 是单例，则将bean 放入单例池中
                    if(beanDefinition.getIsSingleton() == 1){
                        beanMap.put(beanId , bean);
                    }
                }
            }
        }

        return bean;
    }


    private static String getBeanId(Class<?> clazz){

        Class[] interfaces = clazz.getInterfaces();
        if(interfaces != null && interfaces.length == 1){

            String interfaceName = interfaces[0].getSimpleName();

            return interfaceName.substring(0,1).toLowerCase() + interfaceName.substring(1);

        }
        String simpleName = clazz.getSimpleName();
        return simpleName.substring(0,1).toLowerCase() + simpleName.substring(1);
    }



    private static File getFile(String pagePath) {
        String path = AnnotationBeanFactory.class.getResource("/").getPath();

        String basePage = path + pagePath.replace("." , File.separator);

        return new File(basePage);
    }

}
